package com.example.result.books

import android.app.Application
import android.content.Context
import android.content.Intent
import android.os.Environment
import android.util.Log
import androidx.core.content.FileProvider
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.result.BuildConfig
import com.example.result.DefaultDispatch
import com.example.result.IoDispatch
import com.example.result.preference.Config
import com.lly.tboc.zhouyi.Screen.Audio.isAssets
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch
import okhttp3.MultipartBody
import okhttp3.RequestBody.Companion.asRequestBody
import java.io.File
import javax.inject.Inject

@HiltViewModel
class BooksViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    val context: Application,
    @IoDispatch val dispatcherIO: CoroutineDispatcher,
    @DefaultDispatch val dispatcherDefault: CoroutineDispatcher,
    private val uploadFileApi: com.lly.tboc.zhouyi.api.UploadFileApi,
) :
    ViewModel(), DirectoryChange, DirectoryManager, FileOperation {
    private val _message = MutableStateFlow("")

    override val recentExplorer: Flow<List<String>> =
        context.recentExplorerDataStore.data.map { it.bookMarks }
    private var _bookSortType =
        MutableStateFlow(BookSortType(SortType.Asc, SortCategory.Name))
    override val currentBookSort: StateFlow<BookSortType> = _bookSortType.asStateFlow()
    private val _books = MutableStateFlow<List<Book>>(emptyList())
    val books = combine(_books, _bookSortType) { books, bookSortType ->
        when (bookSortType.sortCategory) {
            SortCategory.TotalSpace -> {
                when (bookSortType.sortType) {
                    SortType.Asc -> books.sortedBy { it.totalSpace }
                    SortType.Desc -> books.sortedByDescending { it.totalSpace }
                }
            }

            SortCategory.ModifierTime -> {
                when (bookSortType.sortType) {
                    SortType.Asc -> books.sortedBy { it.modifiedTime }
                    SortType.Desc -> books.sortedByDescending { it.modifiedTime }
                }

            }

            SortCategory.Name -> {
                when (bookSortType.sortType) {
                    SortType.Asc -> books.sortedBy { it.name }
                    SortType.Desc -> books.sortedByDescending { it.name }
                }

            }
        }

    }

    override fun sort(bookSortType: BookSortType) {
        this._bookSortType.value = bookSortType
        viewModelScope.launch {

            context.recentBookSortDataStore.updateData {
                BookSortInfo(
                    sortType = bookSortType.sortType.name,
                    sortCategory = bookSortType.sortCategory.name
                )
            }
        }
    }

    /**UI需要显示的消息，*/
    val message = _message.asStateFlow()
    fun afterMessageShow() {
        _message.value = ""
    }


    private fun setCurrentDir(book: Book?) {
        savedStateHandle["currentDir"] = book
    }

    override val currentDir = savedStateHandle.getStateFlow<Book?>("currentDir", null)
    val bookMarks by lazy { context.bookMarksDataStore.data }
    val defaultBookMarks by lazy {
        arrayOf(
            ASSET_PREFIX,
            context.getExternalFilesDir(Environment.DIRECTORY_DOCUMENTS)!!.absolutePath,
            Config.getCrashDir(context)?.path ?: "",
            Environment.getExternalStorageDirectory().path
        )
    }

    init {
        viewModelScope.launch(dispatcherDefault) {
            currentDir.filter { it != null }
                .map { it?.path() }
                .collect { path ->
                    if (path?.isNotEmpty() == true) {
                        context.recentExplorerDataStore.updateData {
                            val bookMarks = arrayListOf(path).apply {
                                addAll(it.bookMarks.filter { it != path }.take(9))
                            }
                            BookMarks(bookMarks)
                        }
                    }
                }
        }
        viewModelScope.launch(dispatcherDefault) {
            val sortInfo = context.recentBookSortDataStore.data.first()
            _bookSortType.value = BookSortType(
                sortType = SortType.valueOf(sortInfo.sortType),
                sortCategory = SortCategory.valueOf(sortInfo.sortCategory)
            )
        }
    }

    private fun getAssetBooks(parentPath: String): List<Book> {
        val assets = context.resources.assets

        return assets.list(parentPath)?.filter { !BuildConfig.isExample || it == "README.md" }
            ?.map {
                Book(
                    "$ASSET_PREFIX$parentPath",
                    it,
                    assets.list(if (parentPath.isNotEmpty()) "$parentPath/${it}" else "$parentPath${it}")
                        ?.isNotEmpty() == true
                )
            } ?: emptyList()
    }

    private fun requestFileBooks(path: String) {
        _books.value = emptyList()
        viewModelScope.launch(dispatcherIO) {
            _books.value = if (path.isAssets()) {
                getAssetBooks(path.replace(ASSET_PREFIX, ""))
            } else {
                getMyFileBooks(path)
            }
        }
    }

    private fun getMyFileBooks(parentPath: String): List<Book> {
        return File(parentPath).listFiles()?.map {
            Book(parentPath, it.name, it.isDirectory, it.totalSpace, it.lastModified())
        } ?: emptyList()
    }


    override fun saveToFile(content: String, name: String) {
        viewModelScope.launch(Dispatchers.IO) {
            val path = doSaveToFile(context, name, content)
            _message.emit("文件已经保存到:${path.path}")
        }
    }

    override fun addBookMark(bookMark: String) {
        viewModelScope.launch {
            var hasExist = false
            context.bookMarksDataStore.updateData {
                hasExist = it.bookMarks.contains(bookMark)
                if (hasExist) {
                    it
                } else {
                    val bookMarks = it.bookMarks.toMutableList()
                    bookMarks.add(bookMark)
                    it.copy(bookMarks = bookMarks)
                }
            }
//            Log.e("setBookMark", updateData.toString())
            _message.value = if (hasExist) "已存在该书签" else "已设置该书签"
        }
    }

    override fun removeBookMark(bookMark: String) {
        viewModelScope.launch {
            context.bookMarksDataStore.updateData {
                val bookMarks = it.bookMarks.filterNot { it == bookMark }
                it.copy(bookMarks = bookMarks)
            }
//            Log.e("setBookMark", updateData.toString())
            _message.value = "已删除该书签"
        }

    }

    override fun createFile(name: String) {
        kotlin.runCatching {
            val path = File(currentDir.value?.path() ?: "", name)
            path.outputStream().bufferedWriter().use { file ->
                file.write("")
            }
        }.onFailure {
            _message.value = it.message ?: "failed:createFile $name"
        }
    }


    override fun moveDown(book: Book) {
        if (book.isDir) {
            setCurrentDir(book)
            val path = book.path()
            requestFileBooks(path)
        }
    }

    override fun moveUp() {
        currentDir.value?.let { book ->
            val parentPath = book.parentPath
            setCurrentDir(convertPathToDir(parentPath))
            Log.e("moveUp", "parentPath:$parentPath ${book.name} ")
            requestFileBooks(parentPath)
        }

    }

    override fun refresh() {
        currentDir.value?.path()?.let {
            requestFileBooks(it)
        }
    }

    override fun switchTo(path: String) {
        setCurrentDir(convertPathToDir(path))
        requestFileBooks(path)

    }


    private fun convertPathToDir(path: String): Book {
        val prefix: String = if (path.isAssets()) {
            ASSET_PREFIX
        } else if (path.startsWith(FILE_PREFIX)) {
            FILE_PREFIX
        } else {
            "/"
        }
        val s = path.replaceFirst(prefix, "")
        return s.split('/').filter { it.isNotEmpty() }.let {
            Log.e("convertPathToDir", "$path:$it")
            if (it.size >= 2) {
                Book(
                    prefix + it.subList(0, it.size - 1).joinToString("/"), it[it.size - 1], true
                )

            } else if (it.isNotEmpty()) {
                Book(prefix, it[0], true)
            } else {
                Book(prefix, "", true)
            }
        }
    }

    override fun uploadFile(path: String) {
        viewModelScope.launch(dispatcherIO) {
            kotlin.runCatching {
                val file = File(path)
                val name = file.name
                val requestFile = file.asRequestBody()
                val formData = MultipartBody.Part.createFormData("file", name, requestFile)
                val responseBody = uploadFileApi.upLoadFile(formData)
                _message.emit(responseBody.string())

            }.onFailure {
                if (it is CancellationException) {
                    throw it
                } else {
                    it.printStackTrace()
                    _message.emit(it.toString())
                }
            }
        }
    }

    override fun shareFile(context: Context, path: String) {
        try {
            val intent = Intent(Intent.ACTION_SEND)
            val uri = FileProvider.getUriForFile(
                context,
                "${BuildConfig.APPLICATION_ID}.fileprovider",
                File(path)
            )
            intent.type = "text/plain"
            intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
            intent.flags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
            intent.putExtra(Intent.EXTRA_STREAM, uri) // 添加附件，附件为file对象
            context.startActivity(intent) // 调用系统的mail客户端进行发送
        } catch (e: Exception) {
            e.printStackTrace()
        }

    }
}